package com.sxt.provider.notify.impl;

import com.alibaba.fastjson.JSONObject;
import com.sxt.commons.typeEnum.NotifyLogStateEnum;
import com.sxt.commons.utils.SignMD5Utils;
import com.sxt.dao.mapper.NotifyLogMapper;
import com.sxt.pojo.entity.Cp;
import com.sxt.pojo.entity.NotifyLog;
import com.sxt.pojo.entity.Order;
import com.sxt.pojo.model.NotifyLogExample;
import com.sxt.provider.cp.CpService;
import com.sxt.provider.notify.NotifyLogService;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class NotifyLogServiceImpl implements NotifyLogService {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${api.response.sign.name:}")
    String apiResponseSignName;

    @Value("${api.response.key.name:}")
    String apiResponseKeyName;

    private int[] NotifyFailRate = {
            0, 15, 15, 30, 180, 1800, 1800, 1800, 1800, 3600
    };

    @Autowired
    NotifyLogMapper notifyLogMapper;

    @Autowired
    CpService cpService;

    @Override
    @Transactional
    public List<NotifyLog> getNotifyList(int size) {
        NotifyLogExample notifyLogExample = new NotifyLogExample();
        notifyLogExample.setLimit(size);
        notifyLogExample.setOrderByClause("last_notify_time");
        notifyLogExample.createCriteria().andLastNotifyTimeLessThan(new Date())
                .andStateNotEqualTo(NotifyLogStateEnum.SUCCESS.getType())
                .andStateNotEqualTo(NotifyLogStateEnum.FAIL.getType())
                .andFailCountLessThan((byte) NotifyFailRate.length);
        return notifyLogMapper.selectByExample(notifyLogExample);
    }

    @Override
    @Async
    @Transactional
    public void send(NotifyLog notifyLog) {
        if (notifyLog == null) {
            return;
        }
        if (Objects.equals(notifyLog.getState(), NotifyLogStateEnum.SUCCESS.getType())) {
            return;
        }
        if (notifyLog.getFailCount() >= NotifyFailRate.length) {
            notifyLog.setState(NotifyLogStateEnum.FAIL.getType());
            notifyLogMapper.updateByPrimaryKey(notifyLog);
            return;
        }

        if(StringUtils.equalsIgnoreCase(notifyLog.getNotifyUrl(), "none")) {
            notifyLog.setState(NotifyLogStateEnum.SUCCESS.getType());
            notifyLogMapper.updateByPrimaryKey(notifyLog);
            return;
        }

        if (notifyLog.getOpType() == 1) {
            String resp = sendPostJson(notifyLog.getNotifyUrl(),notifyLog.getNotifyMsg());
            notifyLog.setRsp(resp);
            if (StringUtils.isNotBlank(resp) && StringUtils.equalsIgnoreCase(resp, "success")) {
                notifyLog.setState(NotifyLogStateEnum.SUCCESS.getType());
            } else {
                notifyLog.setState(NotifyLogStateEnum.UNSUCCESS.getType());
                if (notifyLog.getFailCount() >= NotifyFailRate.length - 1) {
                    notifyLog.setState(NotifyLogStateEnum.FAIL.getType());
                } else {
                    notifyLog.setFailCount((byte) (notifyLog.getFailCount() + 1));
                    notifyLog.setLastNotifyTime(
                            org.apache.commons.lang3.time.DateUtils.addSeconds(
                                    new Date(),
                                    NotifyFailRate[notifyLog.getFailCount()]
                            )
                    );
                }
            }
            notifyLogMapper.updateByPrimaryKey(notifyLog);
        }
    }

    @Override
    public void setOrderSuccess(Order order, Cp cp){
        try {
            NotifyLog log = new NotifyLog();
            log.setNotifyUrl(order.getNotifyUrl());
            log.setOpType((byte) 1);
            log.setState((byte) 0);
            log.setTradeNo(order.getTradeNo());
            log.setFailCount((byte) 0);
            log.setCreateTime(new Date());
            log.setLastNotifyTime(new Date());

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            Map<String, Object> msgMaps = new HashMap<>();
            msgMaps.put("state", "0");
            msgMaps.put("message", "成功");
            msgMaps.put("mchId", cp.getId());
            msgMaps.put("outTradeNo", order.getOutTradeNo());
            msgMaps.put("tradeNo", order.getTradeNo());
            msgMaps.put("totalFee", order.getAmount());
            msgMaps.put("type", order.getChannelType());
            msgMaps.put("sign", SignMD5Utils.getSign(msgMaps,cp.getSecretId()));

            log.setNotifyMsg(JSONObject.toJSONString(msgMaps));
            notifyLogMapper.insert(log);
        } catch (Exception e) {
            logger.info(order.getTradeNo()+"回调“置成功”失败："+e.getMessage());
        }

    }

    private static String sendPostJson(String urlPath, String Json) {
        // HttpClient 6.0被抛弃了
        String result = "";
        BufferedReader reader = null;
        try {
            URL url = new URL(urlPath);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("Content-Type","application/json; charset=UTF-8");
            // 设置接收类型否则返回415错误
            //conn.setRequestProperty("accept","*/*")此处为暴力方法设置接受所有类型，以此来防范返回415;
            conn.setRequestProperty("accept","application/json");
            // 往服务器里面发送数据
            if (Json != null && !TextUtils.isEmpty(Json)) {
                byte[] writebytes = Json.getBytes();
                // 设置文件长度
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                //OutputStream outwritestream = conn.getOutputStream();
                DataOutputStream outwritestream = new DataOutputStream(
                        conn.getOutputStream());
                outwritestream.write(Json.getBytes());
                outwritestream.flush();
                outwritestream.close();
            }
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "utf-8");
                sb.append(lines);
            }
            result = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

}
